package utils

import (
	"archive/zip"
	"bufio"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

// FileDownloadAndUnzip 下载 ZIP 文件并解压到指定目录
func FileDownloadAndUnzip(url, destDir string) error {
	// 创建临时文件来保存下载的 ZIP
	tmpFile, err := os.CreateTemp("", "temp*.zip")
	if err != nil {
		return fmt.Errorf("创建临时文件失败: %v", err)
	}
	defer os.Remove(tmpFile.Name()) // 确保临时文件被删除

	// 下载 ZIP 文件
	if err := downloadFile(url, tmpFile); err != nil {
		return fmt.Errorf("下载文件失败: %v", err)
	}
	tmpFile.Close()

	// 解压 ZIP 文件
	if err := FileUnzip(tmpFile.Name(), destDir); err != nil {
		return fmt.Errorf("解压文件失败: %v", err)
	}

	return nil
}

// downloadFile 下载文件并保存到指定的 writer
func downloadFile(url string, writer io.Writer) error {
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("下载失败，HTTP 状态码: %d", resp.StatusCode)
	}

	_, err = io.Copy(writer, resp.Body)
	return err
}

// FileUnzip 解压 ZIP 文件到指定目录
func FileUnzip(zipFile, destDir string) error {
	reader, err := zip.OpenReader(zipFile)
	if err != nil {
		return err
	}
	defer reader.Close()

	for _, file := range reader.File {
		path := filepath.Join(destDir, file.Name)

		if file.FileInfo().IsDir() {
			os.MkdirAll(path, os.ModePerm)
			continue
		}

		if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
			return err
		}

		outFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
		if err != nil {
			return err
		}

		rc, err := file.Open()
		if err != nil {
			outFile.Close()
			return err
		}

		_, err = io.Copy(outFile, rc)
		outFile.Close()
		rc.Close()

		if err != nil {
			return err
		}
	}

	return nil
}

// FilePathExists 检查系统路径是否存在
func FilePathExists(filename string) bool {
	_, err := os.Stat(filename)
	return !os.IsNotExist(err)
}

// FileCreate 创建新文件
func FileCreate(filename string) error {
	f, err := os.Create(filename)
	if err != nil {
		return fmt.Errorf("创建文件失败: %v", err)
	}
	defer f.Close()
	return nil
}

// FileRead 读取整个文件内容
func FileRead(filename string) (string, error) {
	content, err := os.ReadFile(filename)
	if err != nil {
		return "", fmt.Errorf("读取文件失败: %v", err)
	}
	return string(content), nil
}

// FileWrite 写入内容到文件（覆盖原有内容）
func FileWrite(filename string, content string) error {
	err := os.WriteFile(filename, []byte(content), 0644)
	if err != nil {
		return fmt.Errorf("写入文件失败: %v", err)
	}
	return nil
}

// FileAppend 追加内容到文件末尾
func FileAppend(filename string, content string) error {
	f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return fmt.Errorf("打开文件失败: %v", err)
	}
	defer f.Close()

	if _, err = f.WriteString(content); err != nil {
		return fmt.Errorf("追加内容失败: %v", err)
	}
	return nil
}

// FileCopy 复制文件
func FileCopy(src, dst string) error {
	sourceFileStat, err := os.Stat(src)
	if err != nil {
		return fmt.Errorf("获取源文件信息失败: %v", err)
	}

	if !sourceFileStat.Mode().IsRegular() {
		return fmt.Errorf("%s 不是一个常规文件", src)
	}

	source, err := os.Open(src)
	if err != nil {
		return fmt.Errorf("打开源文件失败: %v", err)
	}
	defer source.Close()

	destination, err := os.Create(dst)
	if err != nil {
		return fmt.Errorf("创建目标文件失败: %v", err)
	}
	defer destination.Close()

	_, err = io.Copy(destination, source)
	if err != nil {
		return fmt.Errorf("复制文件内容失败: %v", err)
	}
	return nil
}

// FileMove 移动文件
func FileMove(src, dst string) error {
	err := os.Rename(src, dst)
	if err != nil {
		return fmt.Errorf("移动文件失败: %v", err)
	}
	return nil
}

// FileDelete 删除文件
func FileDelete(filename string) error {
	err := os.Remove(filename)
	if err != nil {
		return fmt.Errorf("删除文件失败: %v", err)
	}
	return nil
}

// FileReadLines 读取文件的所有行
func FileReadLines(filename string) ([]string, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, fmt.Errorf("打开文件失败: %v", err)
	}
	defer file.Close()

	var lines []string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}

	if err := scanner.Err(); err != nil {
		return nil, fmt.Errorf("读取文件行失败: %v", err)
	}

	return lines, nil
}

// FileSize 获取文件大小
func FileSize(filename string) (int64, error) {
	info, err := os.Stat(filename)
	if err != nil {
		return 0, fmt.Errorf("获取文件信息失败: %v", err)
	}
	return info.Size(), nil
}

// FileMkdir 创建目录（如果不存在）
func FileMkdir(path string) error {
	if err := os.MkdirAll(path, os.ModePerm); err != nil {
		return fmt.Errorf("创建目录失败: %v", err)
	}
	return nil
}

// FileIsDir 检查路径是否为目录
func FileIsDir(path string) (bool, error) {
	fileInfo, err := os.Stat(path)
	if err != nil {
		return false, fmt.Errorf("获取路径信息失败: %v", err)
	}
	return fileInfo.IsDir(), nil
}

// FileListDir 列出目录中的所有文件和子目录
func FileListDir(path string) ([]string, error) {
	var files []string
	err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		files = append(files, path)
		return nil
	})
	if err != nil {
		return nil, fmt.Errorf("列出目录内容失败: %v", err)
	}
	return files, nil
}

// FileIsValidFilename 检查给定的字符串是否是有效的文件名
func FileIsValidFilename(filename string) (bool, string) {
	// 检查文件名长度
	if len(filename) == 0 {
		return false, "文件名不能为空"
	}
	if len(filename) > 255 {
		return false, "文件名过长（最大255个字符）"
	}

	// 检查文件名是否包含路径分隔符
	if strings.ContainsAny(filename, "/\\") {
		return false, "文件名不能包含路径分隔符"
	}

	// 检查文件名是否为 "." 或 ".."
	if filename == "." || filename == ".." {
		return false, "文件名不能为 '.' 或 '..'"
	}

	// 检查文件名是否以 "." 开头（隐藏文件）
	if strings.HasPrefix(filename, ".") {
		return false, "文件名不能以 '.' 开头"
	}

	// 检查文件名是否包含非法字符
	validFilenameRegex := regexp.MustCompile(`^[a-zA-Z0-9_\-\\.]+$`)
	if !validFilenameRegex.MatchString(filename) {
		return false, "文件名包含非法字符（只允许字母、数字、下划线、连字符和点）"
	}

	// 检查文件名是否为 Windows 保留名称
	reservedNames := []string{
		"CON", "PRN", "AUX", "NUL",
		"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
		"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
	}
	upperFilename := strings.ToUpper(filename)
	for _, name := range reservedNames {
		if upperFilename == name || strings.HasPrefix(upperFilename, name+".") {
			return false, fmt.Sprintf("文件名不能为保留名称 '%s'", name)
		}
	}

	// 检查文件扩展名
	ext := filepath.Ext(filename)
	if ext == "" {
		return false, "文件名必须包含扩展名"
	}

	return true, ""
}

// FileIsValidDirectoryName 检查给定的字符串是否是有效的目录名
func FileIsValidDirectoryName(dirname string) (bool, string) {
	// 检查目录名长度
	if len(dirname) == 0 {
		return false, "名成不能为空"
	}
	if len(dirname) > 255 {
		return false, "名成过长（最大255个字符）"
	}

	// 检查目录名是否包含路径分隔符
	if strings.ContainsAny(dirname, "/\\") {
		return false, "名成不能包含路径分隔符"
	}

	// 检查目录名是否为 "." 或 ".."
	if dirname == "." || dirname == ".." {
		return false, "名成不能为 '.' 或 '..'"
	}

	// 检查目录名是否包含非法字符
	validDirnameRegex := regexp.MustCompile(`^[a-zA-Z0-9_\-\.]+$`)
	if !validDirnameRegex.MatchString(dirname) {
		return false, "名成包含非法字符（只允许字母、数字、下划线、连字符和点）"
	}

	// 检查目录名是否为 Windows 保留名称
	reservedNames := []string{
		"CON", "PRN", "AUX", "NUL",
		"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
		"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
	}
	upperDirname := strings.ToUpper(dirname)
	for _, name := range reservedNames {
		if upperDirname == name {
			return false, fmt.Sprintf("名成不能为保留名称 '%s'", name)
		}
	}

	return true, ""
}

// FileCreateDirectories 创建给定的目录列表
func FileCreateDirectories(dirs []string) error {
	for _, dir := range dirs {
		// 尝试创建目录
		err := os.MkdirAll(dir, os.ModePerm)
		if err != nil {
			return fmt.Errorf("failed to create directory %s: %w", dir, err)
		}
		fmt.Printf("Directory created: %s\n", dir)
	}
	return nil
}
